package com.caits.lbs.framework.services.impl;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.apache.logging.log4j.LogManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.aliyun.openservices.ClientException;
import com.aliyun.openservices.ServiceException;
import com.aliyun.openservices.oss.OSSClient;
import com.aliyun.openservices.oss.OSSErrorCode;
import com.aliyun.openservices.oss.OSSException;
import com.aliyun.openservices.oss.model.CannedAccessControlList;
import com.aliyun.openservices.oss.model.GetObjectRequest;
import com.aliyun.openservices.oss.model.ObjectMetadata;
import com.caits.lbs.exception.ApiException;
import com.caits.lbs.framework.bean.common.ImageDetail;
import com.caits.lbs.framework.services.BaseService;
import com.caits.lbs.framework.services.UploadImageService;
/**
 * <p>
 * UploadImageServiceImpl
 * </p>
 * <p>
 * 阿里云oss上传图片服务
 * </p>
 * @author 周华彬(zhouhuabin@sinoiov.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>admin</td>
 *          <td>2017年7月3日 上午11:37:42</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
/**
 * <p>UploadImageServiceImpl</p>
 * <p>阿里云oss文件上传实现</p>
 *
 * @author		周华彬(zhouhuabin@sinoiov.com, zhou_hua_bin@163.com)
 * @version		0.0.0
 * <table style="border:1px solid gray;">
 * <tr>
 * <th width="100px">版本号</th><th width="100px">动作</th><th width="100px">修改人</th><th width="100px">修改时间</th>
 * </tr>
 * <!-- 以 Table 方式书写修改历史 -->
 * <tr>
 * <td>0.0.0</td><td>创建类</td><td>admin</td><td>2017年7月3日 下午4:09:59</td>
 * </tr>
 * <tr>
 * <td>XXX</td><td>XXX</td><td>XXX</td><td>XXX</td>
 * </tr>
 * </table>
*/
@Component("uploadImageServiceX")
public class UploadImageServiceImpl implements UploadImageService, BaseService  {
	/** 变量:TODO,类型:org.apache.logging.log4j.Logger */
	private org.apache.logging.log4j.Logger LOG = LogManager.getLogger(getClass());
	/** 变量:TODO,类型:OSSClient */
	public static OSSClient client = null;
	/** 变量:TODO,类型:String */
	@Value("${oss_access_id}")
	private  String oss_access_id = "oss_access_id";
	/** 变量:TODO,类型:String */
	@Value("${oss_access_key}")
	private  String oss_access_key = "oss_access_key";
	/** 变量:TODO,类型:String */
	@Value("${oss_aliyun_writeUrl}")
	private  String oss_aliyun_writeUrl = "oss_aliyun_writeUrl";
	@Value("${oss_aliyun_readUrl}")
	private  String oss_aliyun_readUrl = "oss_aliyun_readUrl";
	
	@Value("${oss_expiration_time}")
	private  long oss_expiration_time = 31536000000l;
	@Value("${oss_bucketName}")
	public  String oss_bucketName="hayll";
	
	/** 变量:支持的文件类型,类型:HashMap<String,String> */
	private static HashMap<String, String> MIME_EXT = new HashMap<String, String>();
	
	static {
		MIME_EXT.put("jpeg", "image/jpeg");
		MIME_EXT.put("jpg", "image/jpeg");
		MIME_EXT.put("jpe", "image/jpeg");
		MIME_EXT.put("gif", "image/gif");
		MIME_EXT.put("zip", "application/zip");
		MIME_EXT.put("xls", "application/msexcel");
		MIME_EXT.put("xlsx", "application/msexcel");
		MIME_EXT.put("doc", "application/msword");
		MIME_EXT.put("apk", "application/vnd.android");
		MIME_EXT.put("html", "text/html");
		MIME_EXT.put("htm", "text/html");
	}

	@Override
	public String imageUpload(ImageDetail uploadImagesVO) throws ApiException {
		if (StringUtils.isEmpty(uploadImagesVO.getBucketName())) {
			LOG.debug("INVALID_PARAM:BucketName为空，将采用默认bucetName:"+oss_bucketName);
			uploadImagesVO.setBucketName(oss_bucketName);
		}
		if (StringUtils.isEmpty(uploadImagesVO.getFileExt())) {
			throw new ApiException("INVALID_PARAM:FileExt为空");
		} else {
			if (uploadImagesVO.getFileExt().substring(0, 1).equals(".")) {
				uploadImagesVO.setFileExt(uploadImagesVO.getFileExt().substring(1, uploadImagesVO.getFileExt().length()));
			}
		}
		if (StringUtils.isEmpty(uploadImagesVO.getImageType())) {
			throw new ApiException("INVALID_PARAM:ImageType为空");
		}
		return uploadImageByOss(uploadImagesVO);
	}

	/**
	 * 上传图片到oss服务器
	 * @param uploadImagesVO
	 * @return
	 * @return 返回String
	 */
	public String uploadImageByOss(ImageDetail uploadImagesVO) {
		String url = "";
		OSSClient localClient = getClient();
		ensureBucket(localClient, uploadImagesVO.getBucketName());
		try {
			// setBucketPublicReadable(uploadImagesVO.getBucketName(),uploadImagesVO.isPublic());
			String key = uploadImagesVO.getImageType() + "/" + String.valueOf(Math.abs(new Random().nextLong())) + "." + uploadImagesVO.getFileExt();
			String mimeType = getMimeByExt(uploadImagesVO.getFileExt());
			Date expire = null;
			if (uploadImagesVO.getExpirationTime() != null) {
				expire = new Date(new Date().getTime() + uploadImagesVO.getExpirationTime());
			}else{
				expire =  new Date(new Date().getTime() + oss_expiration_time);
			}
			uploadFile(uploadImagesVO.getBucketName(), key, uploadImagesVO.getImageBytes(), uploadImagesVO.getConditionMap(), mimeType, expire);
//			url = getResUrl(uploadImagesVO.getBucketName(), key, expire);
			url=oss_aliyun_readUrl+"/"+key;
			// 返回外网地址,替换将http://oss-cn-hangzhou.aliyuncs.com/...替换为http://zjhyl.oss-cn-hangzhou.aliyuncs.com/...
			url = url.replace(".oss-internal.", ".oss.");
			url = url.replace("oss", uploadImagesVO.getBucketName()+".oss");
			LOG.info("上传后的相对路径path:"+key);
		} catch (Exception e) {
			LOG.error("上传文件到OSS异常,bucketName:" + uploadImagesVO.getBucketName(), e);
		}
		return url;
	}

	// 上传文件
	private void uploadFile(String bucketName, String key, byte[] byt, Map<String, String> userMetadataMap, String type, Date expire) throws OSSException, ClientException,
			FileNotFoundException {
		ObjectMetadata objectMeta = new ObjectMetadata();
		if (expire != null)
			objectMeta.setExpirationTime(expire);
		objectMeta.setContentLength(byt.length);
		// 可以在metadata中标记文件类型
		objectMeta.setContentType(type);
		if (null != userMetadataMap && userMetadataMap.size() > 0) {
			for (Map.Entry<String, String> entry : userMetadataMap.entrySet()) {
				objectMeta.addUserMetadata(entry.getKey(), entry.getValue());
			}
		}
		client.putObject(bucketName, key, byte2Input(byt), objectMeta);
	}

	// 创建Bucket.
	private void ensureBucket(OSSClient client, String bucketName) throws OSSException, ClientException {
		try {
			if (!client.doesBucketExist(bucketName)) {
				// 创建bucket
				client.createBucket(bucketName);
			}
		} catch (ServiceException e) {
			if (!OSSErrorCode.BUCKES_ALREADY_EXISTS.equals(e.getErrorCode())) {
				// 如果Bucket已经存在，则忽略
				throw e;
			}
		}
	}

	/**
	 * 删除一个Bucket下的Objects
	 * @param client
	 * @param bucketName
	 * @param objectName
	 * @throws OSSException
	 * @throws ClientException
	 * @return 返回void
	 */
	private void deleteObject(OSSClient client,String bucketName, String objectName) throws OSSException, ClientException {
			// 如果不为空，先删除bucket下的文件
			client.deleteObject(bucketName, objectName);
	}

	// 把Bucket设置为所有人可读
	public void setBucketPublicReadable(String bucketName, boolean isPublic) throws OSSException, ClientException {
		// //创建bucket
		// client.createBucket(bucketName);
		if (isPublic) {
			// 设置bucket的访问权限，public-read-write权限
			client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
		} else {
			client.setBucketAcl(bucketName, CannedAccessControlList.Private);
		}

	}

	/**
	 * 获得图片路径
	 * @param client
	 * @param bucketName
	 * @param key
	 * @return
	 * @throws OSSException
	 * @throws ClientException
	 * @return 返回String
	 */
	private String getResUrl(String bucketName, String key, Date expiration) throws OSSException, ClientException {
		OSSClient localClient = getClient();
		URL url = localClient.generatePresignedUrl(bucketName, key, expiration);
		return url.toString();
	}

	/**
	 * 下载文件
	 * @param bucketName
	 * @param key
	 * @param filename
	 * @throws OSSException
	 * @throws ClientException
	 * @return 返回void
	 */
	public void downloadFile(String bucketName, String key, String filename) throws OSSException, ClientException {
		OSSClient localClient = getClient();
		localClient.getObject(new GetObjectRequest(bucketName, key), new File(filename));
	}

	/**
	 * 获取扩展名
	 * @param ext
	 * @return
	 * @return 返回String
	 */
	private String getMimeByExt(String ext) {
		if (ext == null || ext.length() == 0)
			return "application/octet-stream";
		String ret = MIME_EXT.get(ext.toLowerCase());
		return ret != null ? ret : "application/octet-stream";
	}

	/**
	 * FIXME 
	 * @param buf
	 * @return 
	 * @return 返回InputStream
	 */
	private final InputStream byte2Input(byte[] buf) {
		return new ByteArrayInputStream(buf);
	}

	/**
	 * FIXME
	 * @return 返回void
	 */
	private OSSClient getClient() {
		if (client == null) {
			client = new OSSClient(oss_aliyun_writeUrl, oss_access_id, oss_access_key);
		}
		return client;
	}

	/* (non-Javadoc)
	 * @see com.hyl.app.common.service.impl.BaseService#resetParameter()
	 */
	@Override
	public void resetParameter() {
		LOG.info("更新oss文件上传服务UploadImageServiceImpl参数完毕.");
	}

}
